跟著做出來的範例
成本圖:
內容概要 三個 input 來做加入書本的動作,輸入內容後會在下方存入它們的資料,並且有刪除的功能,資料可以儲存在網頁上不會被重新整理刷掉 會跑出視窗當填寫不完整或是成功執行動作的時候 頁面使用簡單的 Bootrap 框架製作 有帶入一些 JSON,ES6-class 的元素 HTML+boostrap: 前置作業 使用fontawesome 來做 icon
1 <script src ="https://kit.fontawesome.com/2ae9e2b502.js" crossorigin ="anonymous" > </script >
使用bootswatch 來做框架這樣就不用處理 CSS 瞜
1 2 <linkrel="stylesheet"href="https://bootswatch.com/4/ye``ti/bootstrap.min.css">
使用範例:
h1 裏面包含了 icon 的使用 fa 的部分還有<i>
tag text-primary 是 bootstrap 1 2 <h1 class ="display-4" > <i class ="fa fa-book-open text-center text-primary" > </i > My<span class ="text-primary" > Book</span >List </h1 >
JS 使用 class 建構 Book 這個物件
1 2 3 4 5 6 7 class Book { constructor (title, author, isbn ) { this .title = title; this .author = author; this .isbn = isbn; } }
接下來會分成數個部分來解釋這整份 JS 內容:
UI class:處理有關 UI 的任務(使用者會看到並且操作的地方) Store class:處理 storage 相關任務 Event:在 list 裡面展示書本 Event:加入書本 Event:移除書本 UI class 有關於 UI 的內容會有五個相關的 method 來處理:
displayBooks 新增的書本會放在這個區域下方
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 static displayBooKs ( ) { const books = Store.getBooks(); books.forEach((book ) => UI.addBookToList(book)); }
addBookToList 書本加入 display 區域的”方法”呈現在這部分:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 static addBookToList (book ) { const list = document .querySelector('#book-list' ); const row = document .createElement('tr' ); row.innerHTML = ` <td>${book.title} </td> <td>${book.author} </td> <td>${book.isbn} </td> <td><a href="#" class="btn btn-danger btn-sm delete">X</a></td> ` list.appendChild(row); }
clearFields 設定好這個清空功能後在兩個狀態下會清空欄位
加入書本成功後會呼叫這個函式動作就會清空欄位詳見(Event: 加入書本)區域 重新整理頁面因為預設值為空(“”) 1 2 3 4 5 6 static clearFields ( ) { document .querySelector('#title' ).value = '' ; document .querySelector('#author' ).value = '' ; document .querySelector('#isbn' ).value = '' ; }
showAlert 一些不熟的方法
createElement - MDN
createTextNode - MDN
appendChild - w3cschool
setTimeout - MDN
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 static showAlert (message, className ) { const div = document .createElement('div' ); div.className = `alert alert-${className} ` ; div.appendChild(document .createTextNode(message)); const container = document .querySelector('.container' ); const form = document .querySelector('#book-form' ); container.insertBefore(div, form) setTimeout (() => document .querySelector('.alert' ).remove(), 3000 ) }
deleteBook 這邊兩個 parentElement 的用意在於位置的關係要砍掉的是<td>
外面的<tr>
contains - w3cschool
classList - MDN
remove - MDN
1 2 3 4 5 6 static deleteBook (el ) { if (el.classList.contains('delete' )) { el.parentElement.parentElement.remove(); } }
Store class 處理 storage 的方法的 class,(local storage 也就是 browser 除非被刪除不然資料會存在那邊) 並且它不能存 object 只能存 string
getBooks 其實就是 return 傳入的書本的 value 陣列
getItem - MDN
在四個需要抓取書本的地方出現:
getBooks 方法本身 UI class displayBooks 要呈現書的地方就抓取了這邊的資料 addBook 方法內 removeBook 方法內 1 2 3 4 5 6 7 8 9 10 11 12 static getBooks ( ) { let books; if (localStorage .getItem('books' ) === null ) { books = []; } else { books = JSON .parse(localStorage .getItem('books' )) } return books; }
addBook 它是功能是在 localStorage 裡面創造鍵與值(key and value)藉由 push 的方式把參數(book)推進去’books’這個陣列裡面
1 2 3 4 5 6 7 static addBook (book ) { const books = Store.getBooks(); books.push(book); localStorage .setItem('books' , JSON .stringify(books)); }
removebook 得先取得已經加入得書的 value,之後根據剛剛的到的資料做做判斷如果符合 isbn 則執行 splice(刪除元素)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 static removebook (isbn ) { const books = Store.getBooks(); books.forEach((book, index ) => { if (book.isbn === isbn) { books.splice(index, 1 ) } }); localStorage .setItem('books' , JSON .stringify(books)); }
事件監聽(addEventListener) Event: 展示書本在 list 裡面 讓頁面在重整後依舊可以顯示出書本在 list 裡面
DOMContentLoaded - MDN
1 document .addEventListener('DOMContentLoaded' , UI.displayBooKs);
Event: 加入書本 先抓取整個 input 區域後加入事件監聽在’submit’上,然後使用取得的事件的值(e),去跑下方判斷式(前提是內容不為空(“”)
preventDefault - MDN
submit_event - MDN
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 document .querySelector('#book-form' ).addEventListener('submit' , (e ) => { e.preventDefault(); const title = document .querySelector('#title' ).value; const author = document .querySelector('#author' ).value; const isbn = document .querySelector('#isbn' ).value; if (title === '' || author === '' || isbn === '' ) { UI.showAlert('Please fill in all fields' , 'danger' ); } else { const book = new Book(title, author, isbn); UI.addBookToList(book); Store.addBook(book); UI.showAlert('Book Added' , 'success' ) UI.clearFields(); } })
Event: 移除書本 一樣抓取完 input 區域後設定事件監聽使用取得的值(e),去呼叫下方的靜態方法
UI 的部分刪除完成後再刪除 Store 的部分重新整理頁面就不會再跑回來瞜
1 2 3 4 5 6 7 8 9 10 11 document .querySelector('#book-list' ).addEventListener('click' , (e ) => { UI.deleteBook(e.target) Store.removebook(e.target.parentElement.previousElementSibling.textContent); UI.showAlert('Book Removed' , 'success' ) })